﻿/*
	Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include"Animate.h"
#include "../node/Sprite.h"
#include "../base/Debuger.h"
#include<memory>
namespace SkyEngine2d
{
	
	Animate::Animate()
		:m_animation(nullptr)
		,m_currentFrameIndex(0)
		,m_nextFrameIndex(0)
		,m_displayedCount(0)
		,m_currentTarget(nullptr)
	{
		
	}
	
	Animate::~Animate()
	{
	}
	
	const AnimationSharedPtr & Animate::getAnimation() const
	{
		return m_animation;
	}
	
	int Animate::getCurrentFrameIndex()
	{
		return m_currentFrameIndex;
	}
	
	AnimateSharedPtr Animate::create(const std::shared_ptr<Animation> & animation)
	{
		auto p = std::shared_ptr<Animate>(new Animate);
		if (p->initWithAnimation(animation))
		{
			return std::move(p);
		}
		return nullptr;
	}
	
	ActionSharedPtr Animate::convertToActionUptr()
	{
		return std::dynamic_pointer_cast<ActionTime>(shared_from_this());
	
	}
	
	bool Animate::initWithAnimation(const std::shared_ptr<Animation> & animation)
	{
		if (animation==nullptr)
		{
			DebugWarning("animation 不能为 null ");
			return false;
		}
	
		//设置动画播放总时长
		float duration = animation->getDisplayOnceDuration();
		this->setDuration(duration*animation->getDisplayTimes());
	
		m_nextFrameIndex = 0;
		this->setAnimation(animation);
		m_displayedCount = 0;
		m_timePerFrame.reserve(animation->getFrameCount());
		float time = 0;
		for (int i = 0; i < animation->getFrameCount(); i++)
		{
			m_timePerFrame.push_back(time += animation->getFrameDealy(i));
		}
	
		return true;
	}
	
	bool Animate::setActionTarget(IActableObject* obj)
	{
		auto p = dynamic_cast<IAnimatableObject*>(obj);
		if (!p)
		{
			return false;
		}
	
		m_currentTarget = p;
	
		return true;
	}
	
	void Animate::update(float ratio)
	{
		float currTimes = 0;
	
		if (ratio<=1.0f)
		{
			int times = m_animation->getDisplayTimes();
			float currDisplayCount = times*ratio;
			//如果当前的播放次数大于 m_displayedCount 则 代表开始新的一次动画播放 
			if ((int)currDisplayCount>m_displayedCount)
			{
				m_nextFrameIndex = 0;
				m_displayedCount++;
			}
			currTimes = fmodf(currDisplayCount*m_animation->getDisplayOnceDuration(),m_animation->getDisplayOnceDuration());
		}
	
		// 获取动画帧 
		auto & aframes = m_animation->getAnimationFrams();
		for (;m_nextFrameIndex<(int)aframes.size();)
		{
			//DebugInfor("for in");
			float time = m_timePerFrame.at(m_nextFrameIndex);
			//当前时间大于执行时间
			if (currTimes >= (time-0.02f))
			{
				m_currentFrameIndex = m_nextFrameIndex;
				//DebugInfor("current_index %d",m_currentFrameIndex);
				auto aframe = aframes.at(m_currentFrameIndex);
				auto target = m_currentTarget;
				DebugerAssert(target, "当前动画的目标为空");
				if (target)
				{
					target->setSpriteFrame(aframe->getSpriteFrame());
				}
				m_nextFrameIndex++; //只有当帧执行成功时 才换下一个索引
			}
			else
			{
				break;
			}
		}
	}
	
	void Animate::setAnimation(const std::shared_ptr<Animation> & animation)
	{
		m_animation = animation;
	}
	
	bool Animate::startWithTarget(IActableObject* target)
	{
		if (!ActionInterval::startWithTarget(target))
		{
			return false;
		}
		if (m_currentTarget)
		{
			m_origFrame = m_currentTarget->getSpriteFrame();
		}
		m_nextFrameIndex = 0;
		m_displayedCount = 0;
	
		return true;
	}
	
	void Animate::stop()
	{
		if (!m_currentTarget)
		{
			return;
		}
	
		if (m_animation->isRestOriginalFrame())
		{
			m_currentTarget->setSpriteFrame(m_origFrame);
		}
	
		ActionInterval::stop();
	}
	
	//////////////////////////////////////////////////////////////////////////////////
	
	Animation::Animation()
		: m_isRestOriginalFrame(true)
		, m_duration(0)
		, m_displayTimes(0)
		, m_framesCount(0)
	{
	
	}
	
	Animation::~Animation()
	{
	
	}
	
	bool Animation::init()
	{
		return true;
	}
	
	
	bool Animation::initWithAnimationFrame(const std::vector<std::shared_ptr<AnimationFrame>>& frams, int times)
	{
		m_displayTimes = times;
		this->addFrames(frams);
		return true;
	}
	
	
	
	bool Animation::initWithSpriteFrame(const std::vector<std::shared_ptr<SpriteFrame>> & frames, float delay, int times)
	{
		m_displayTimes = times;
		for (auto & sprite_frame : frames)
		{
			m_frames.push_back(AnimationFrame::create(sprite_frame, delay));
		}
		m_framesCount += m_frames.size();
		m_duration = m_framesCount * delay;
	
		return true;
	}
	
	std::shared_ptr<Animation> Animation::create()
	{
		auto p = std::shared_ptr<Animation>(new Animation);
		if (p->init())
		{
			return std::move(p);
		}
		return nullptr;
	}
	
	
	std::shared_ptr<Animation> Animation::create(const std::vector<std::shared_ptr<SpriteFrame>> & frames, float delay /*= 0.0f*/, int times /*= 1*/)
	{
		auto p = std::shared_ptr<Animation>(new Animation);
		if (p->initWithSpriteFrame(frames, delay, times))
		{
			return std::move(p);
		}
		return nullptr;
	}
	
	std::shared_ptr<Animation> Animation::create(const std::vector<std::shared_ptr<AnimationFrame>> & frames, int times /*=1*/)
	{
		auto p = std::shared_ptr<Animation>(new Animation);
		if (p->initWithAnimationFrame(frames, times))
		{
			return std::move(p);
		}
		return nullptr;
	}
	
	void Animation::addFrames(const std::vector<std::shared_ptr<AnimationFrame>> & frames)
	{
		m_framesCount += frames.size();
		for (auto & v : frames)
		{
			m_duration += v->getDealy();
			m_frames.push_back(v);
		}
	}
	
	void Animation::addFrame(const AnimationFrameSharedPtr & frame)
	{
		m_framesCount++;
		m_frames.push_back(frame);
		m_duration += frame->getDealy();
	}
	
	const std::vector<std::shared_ptr<AnimationFrame>>& Animation::getAnimationFrams() const
	{
		return m_frames;
	}
	
	int Animation::getDisplayTimes() const
	{
		return m_displayTimes;
	}
	
	void Animation::setDisplayTimes(int times)
	{
		m_displayTimes = times;
	}
	
	float Animation::getDisplayOnceDuration() const
	{
		return m_duration;
	}
	
	int Animation::getFrameCount() const
	{
		return m_framesCount;
	}
	
	float Animation::getFrameDealy(int index) const
	{
		if (index >= m_framesCount)
		{
			return 0;
		}
	
		return m_frames.at(index)->getDealy();
	}
	
	bool Animation::isRestOriginalFrame() const
	{
		return m_isRestOriginalFrame;
	}
	
	void Animation::setRestOriginalFrame(bool rest)
	{
		m_isRestOriginalFrame = rest;
	}
	
	
	/////////////////////////////////////////////////////////////////////////////////////
	
	AnimationFrame::~AnimationFrame()
	{
	
	}
	
	AnimationFrame::AnimationFrame()
	{
	}
	
	AnimationFrameSharedPtr AnimationFrame::create(const SpriteFrameSharedPtr & sf, float dealy)
	{
		auto p = std::shared_ptr<AnimationFrame>(new AnimationFrame);
		if (p->init(sf,dealy))
		{
			return std::move(p);
		}
		return nullptr;
	}
	
	
	float AnimationFrame::getDealy() const
	{
		return m_dealy;
	}
	
	bool AnimationFrame::init(const std::shared_ptr<SpriteFrame> & sprite_frame, float dealy)
	{
		this->m_spriteFrame = sprite_frame;
		this->m_dealy = dealy;
		return true;
	}
}
